package com.tansun.easycare.rule.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.stereotype.Component;

import com.tansun.easycare.rule.datamodel.model.DataModel;


/**
 * xml 文件 读写 修改
 *
 * @author kuanglishi
 */
@Component
public class ObjectXmlTool {
    /**
     *
     * @param obj
     * @param filePath
     * @param dateFormat
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws IOException
     * @throws DocumentException
     */
    public void writeXml(Object obj, String filePath, String dateFormat, String idfFieldName, String labelRoot) throws IllegalArgumentException, IllegalAccessException, IOException, DocumentException {

        File file = new File(filePath.toString().replace("file:/", ""));
        Element mapping;
        Document document;
        if (!file.exists()) {
            document = DocumentHelper.createDocument();
            mapping = document.addElement("mapping");
        } else {
            SAXReader reader = new SAXReader();
            document = reader.read(file);
            mapping = document.getRootElement();
        }
        Element root;
        //父子类属性
        Field[] field = this.linkArray(obj.getClass().getDeclaredFields(), obj.getClass().getSuperclass().getDeclaredFields());
        root = this.getElementIfExist(obj, idfFieldName, mapping);
        if (root != null) {

            this.resetElementValue(obj, root, dateFormat);
        } else {
            root = mapping.addElement(labelRoot);

            for (int i = 0; i < field.length; i++) { //模型
                if ("interface java.util.List".equals(field[i].getType().toString())) {
                    List<Object> attrList = (List<Object>) this.getField(field[i], obj, dateFormat);
                    if (attrList != null) {
                        for (Object a : attrList) {  //属性
                            Element element = root.addElement("field");  //field 为自定义   TODO
                            Field[] fieldSub = this.linkArray(a.getClass().getDeclaredFields(), a.getClass().getSuperclass().getDeclaredFields());
                            for (int j = 0; j < fieldSub.length; j++) {
                                element.addAttribute(fieldSub[j].getName(), (String) this.getField(fieldSub[j], a, dateFormat));
                            }
                        }
                    }
                } else {
                    root.addAttribute(field[i].getName(), (String) this.getField(field[i], obj, dateFormat));
                }
            }
        }
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");   // 设置XML文件的编码格式
        FileOutputStream fs = new FileOutputStream(filePath.toString().replace("file:/", ""));
        XMLWriter writer = new XMLWriter(fs, format);
        writer.setEscapeText(false);
        writer.write(document);
        writer.flush();
        writer.close();
        fs.close();
    }

    private void resetElementValue(Object obj, Element root, String dateFormat) throws IllegalArgumentException, IllegalAccessException {
        for (Iterator i = root.attributeIterator(); i.hasNext(); ) {
            Attribute a = (Attribute) i.next();
            a.setText(this.getFieldStringValue(a.getName(), obj, dateFormat).toString());
        }
    }

    /**
     * 根据属性名获取
     */
    private Element getElementIfExist(Object obj, String idfFieldName, Element root) throws IllegalArgumentException, IllegalAccessException {
        if (idfFieldName == null) return null;
        for (Iterator i = root.elementIterator(); i.hasNext(); ) {
            Element c = (Element) i.next();
            for (Iterator ii = c.attributeIterator(); ii.hasNext(); ) {
                Attribute a = (Attribute) ii.next();
                //System.out.println(idfFieldName+" "+a.getName()+" "+c.getStringValue()+" "+this.getFieldStringValue(idfFieldName,obj));
                if (idfFieldName.equals(a.getName()) && a.getStringValue().equals(this.getFieldStringValue(idfFieldName, obj))) {
                    return c;
                }
            }
        }
        return null;
    }

    /**
     * 获取对应属性值
     */
    private Object getFieldStringValue(String idfFieldName, Object obj) throws IllegalArgumentException, IllegalAccessException {
        Field[] f = linkArray(obj.getClass().getDeclaredFields(), obj.getClass().getSuperclass().getDeclaredFields());
        for (Field o : f) {
            if (idfFieldName.equals(o.getName())) {
                return this.getField(o, obj, null);
            }
        }
        return null;
    }

    /**
     * 获取对应属性值
     */
    private Object getFieldStringValue(String idfFieldName, Object obj, String formatDate) throws IllegalArgumentException, IllegalAccessException {
        Field[] f = linkArray(obj.getClass().getDeclaredFields(), obj.getClass().getSuperclass().getDeclaredFields());
        for (Field o : f) {
            if (idfFieldName.equals(o.getName())) {
                return this.getField(o, obj, formatDate);
            }
        }
        return null;
    }

    /**
     * @param field  属性对象
     * @param object 属性所属类对象
     * @function:获得属性值
     */
    private Object getField(Field field, Object object, String dateFormat) throws IllegalArgumentException, IllegalAccessException {
        field.setAccessible(true);//设置属性可以修改    
        // System.out.println(field.getType().toString()+field.get(object));
        if ("interface java.util.List".equals(field.getType().toString()) || "interface java.util.Set".equals(field.getType().toString())) {
            return field.get(object);
        } else if ("class java.util.Date".equals(field.getType().toString()) && field.get(object) != null) {
            SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
            return formatter.format(field.get(object));
        } else {
            return String.valueOf(field.get(object) == null ? "" : field.get(object));
        }
    }

    /**
     * 获取根节点下的一级节点
     *
     * @param className  对象类
     * @param filePath   路径
     * @param dateformat 日期格式
     */
    public List getAll(String className, String filePath, String dateformat) throws DocumentException, InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchMethodException, ParseException {
        List list = new ArrayList();
        File file = new File(filePath.toString().replace("file:/", ""));
        if (!file.exists()) {
            throw new DocumentException("获取数据失败");
//			return list;
        }
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element root = document.getRootElement();

        for (Iterator c = root.elementIterator(); c.hasNext(); ) {
            Element elementSub = (Element) c.next();
            list.add(initBean(className, elementSub, false, dateformat, null));
        }
        return list;
    }

    /**
     * @param className 要初始化bean 的类名 DataModel.class.toString().substring(6,DataModel.class.toString().length()
     *                  )
     * @param element   文档元素
     * @param flag      是否递归解析子节点
     * @function:通过xml中的内容初始化bean
     */
    private Object initBean(String className, Element element, boolean flag, String dateFormat, String secClassName) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException, ClassNotFoundException, ParseException {
        Object obj = Class.forName(className).newInstance();
        Field[] field = this.linkArray(obj.getClass().getDeclaredFields(), obj.getClass().getSuperclass().getDeclaredFields());
        for (Iterator it = element.attributeIterator(); it.hasNext(); ) {//遍历当前节点的所有属性
            Attribute attribute = (Attribute) it.next();
            for (int i = 0; i < field.length; i++) {  //根据xml内容赋值到对象中，使用对象中默认值不需要重新赋值
                if (field[i].getName().equals(attribute.getName())) {
                    String value = attribute.getText();
                    Date dateValue;
                    if ("class java.util.Date".equals(field[i].getType().toString())) {
                        SimpleDateFormat df = new SimpleDateFormat(dateFormat);
                        if ("".equals(value)) {
                            dateValue = null;
                        } else {
                            dateValue = df.parse(value);
                        }

                        this.invokeMethod(this.setMethodName(field[i].getName()), obj, dateValue, Date.class);
                    } else {
                        this.invokeMethod(this.setMethodName(field[i].getName()), obj, value, String.class);
                    }

                }
            }
        }

        if (flag == true) {//递归子节点  子节点类别不一致
            List<Element> subElements = element.elements();
            List list = new ArrayList();
            for (Element subElement : subElements) {
                list.add(initBean(secClassName, subElement, false, dateFormat, null));
            }
            for (int i = 0; i < field.length; i++) {
                if ("interface java.util.List".equals(field[i].getType().toString())) {
                    this.invokeMethod(this.setMethodName(field[i].getName()), obj, list, List.class);
                }
            }
        }
        return obj;
    }

    /**
     * 连接两个数组
     */
    private Field[] linkArray(Field[] a1, Field[] a2) {
        if (a1 == null && a2 == null) return null;
        if (a1 == null && a2 != null) return a2;
        if (a1 != null && a2 == null) return a1;
        Field[] aNew = new Field[a1.length + a2.length];
        int index = 0;
        for (Field f : a1) {
            aNew[index] = f;
            index++;
        }
        for (Field f : a2) {
            aNew[index] = f;
            index++;
        }
        return aNew;
    }

    /**
     * @function:通过属性生成set方法名
     */
    private String setMethodName(String str) {
        return "set" + firstToUpperCase(str);
    }

    private String getMethodName(String str) {
        return "get" + firstToUpperCase(str);
    }

    /**
     * 首字母大写
     */
    private String firstToUpperCase(String str) {
        return Character.toUpperCase(str.charAt(0)) + str.substring(1);
    }

    /**
     * @param methodName 方法名
     * @param object     方法所在对象
     * @function:执行方法
     */
    private Object invokeMethod(String methodName, Object object) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
        Method method = object.getClass().getMethod(methodName);

        return method.invoke(object);
    }

    /**
     * @param methodName 方法名
     * @param object     方法所在对象
     * @param value      方法中的参数值
     * @function:执行方法
     */
    private void invokeMethod(String methodName, Object object, Object value, Class type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
        try {
            Method method = object.getClass().getMethod(methodName, type);
            method.invoke(object, value);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            try {
                String txt = "";
                if (object == null) {
                    txt = "object==null";
                } else {
                    txt += object.toString();
                }
                FileUtils.write(new File("E:/exception2.txt"), txt.toString() + ",methodName=" + methodName + ",typeName=" + type.getName());
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }

    }

    /**
     * 删除  mapping下节点
     *
     * @param value        属性值
     * @param filePath     储存路径
     * @param idfFieldName 识别属性名
     */
    public boolean delectDataModel(String value, String filePath, String idfFieldName) throws DocumentException, IllegalArgumentException, IllegalAccessException, IOException {
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element mapping = document.getRootElement();
        Element root;
        root = this.getElementIfExistByValue(value, idfFieldName, mapping);
        if (root == null) {
            return false;
        }
        mapping.remove(root);
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");   // 设置XML文件的编码格式
        FileOutputStream fs = new FileOutputStream(filePath.toString().replace("file:/", ""));
        XMLWriter writer = new XMLWriter(fs, format);
        writer.setEscapeText(false);
        writer.write(document);
        writer.flush();
        writer.close();
        fs.close();
        return true;
    }

    /**
     * 根据某个属性值  获取节点
     *
     * @param value        属性值
     * @param idfFieldName 属性名
     * @param mapping      上级节点
     */
    private Element getElementIfExistByValue(String value, String idfFieldName, Element mapping) {
        if (idfFieldName == null) return null;
        for (Iterator i = mapping.elementIterator(); i.hasNext(); ) {
            Element c = (Element) i.next();
            for (Iterator ii = c.attributeIterator(); ii.hasNext(); ) {
                Attribute a = (Attribute) ii.next();
                if (idfFieldName.equals(a.getName()) && a.getStringValue().equals(value)) {
                    return c;
                }
            }
        }
        return null;
    }

    /**
     * 获取二级属性列表
     *
     * @param pname      class节点名称
     * @param className  类名
     * @param filePath   文件存储路径
     * @param dateformat 日期格式化
     */
    public List getAllSecond(String pname, String idfFieldName, String className, String filePath, String dateformat) throws DocumentException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException, ClassNotFoundException, ParseException {
        List list = new ArrayList();
        File file = new File(filePath.toString().replace("file:/", ""));
        if (!file.exists()) {
            throw new DocumentException("获取数据失败");
//			return list;
        }
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element mapping = document.getRootElement();
        Element root;
        root = this.getElementIfExistByValue(pname, idfFieldName, mapping);
        if (root == null) return null;
        for (Iterator i = root.elementIterator(); i.hasNext(); ) {
            Element a = (Element) i.next();
            Object o = initBean(className, a, false, dateformat, null);
            list.add(o);
        }
        return list;
    }

    /**
     * 删除field 节点
     *
     * @param pname        class节点名称
     * @param name         field 节点名称
     * @param idfFieldName 识别属性名
     * @param filePath     存储文件路径
     */
    public boolean delectSecondAttr(String pname, String name, String idfFieldName, String filePath) throws DocumentException, IOException {

        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element mapping = document.getRootElement();
        Element dm;
        dm = this.getElementIfExistByValue(pname, idfFieldName, mapping);
        if (dm == null) return false;
        Element a = this.getElementIfExistByValue(name, idfFieldName, dm);
        if (a == null) return false;
        dm.remove(a);
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");   // 设置XML文件的编码格式
        FileOutputStream fs = new FileOutputStream(filePath.toString().replace("file:/", ""));
        XMLWriter writer = new XMLWriter(fs, format);
        writer.setEscapeText(false);
        writer.write(document);
        writer.flush();
        writer.close();
        fs.close();
        return true;
    }

    /**
     * @param typeList 如果为null  不返回
     */
    public List getFirstByAttr(List<String> typeList, String idfAttrName, String className, String filePath,
                               String dateformat) throws DocumentException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException, ClassNotFoundException, ParseException {
        List list = new ArrayList();
        if (typeList == null) return list;
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element root = document.getRootElement();
        for (Iterator i = root.elementIterator(); i.hasNext(); ) {
            Element elementSub = (Element) i.next();
            for (Iterator ii = elementSub.attributeIterator(); ii.hasNext(); ) {
                Attribute a = (Attribute) ii.next();
                if (idfAttrName.equals(a.getName()) && typeList.contains(a.getStringValue())) {
                    list.add(initBean(className, elementSub, false, dateformat, null));
                    break;
                }
            }
        }
        return list;
    }

    /**
     * 保存二级节点
     */
    public boolean writeSecondObj(String pname, String idfDmName, Object obj, String filePath,
                                  String dateformat, String labelSecond, String idfAttrName) throws DocumentException, IllegalArgumentException, IllegalAccessException, IOException {
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element mapping = document.getRootElement();
        Element root;
        //父子类属性
        Field[] field = this.linkArray(obj.getClass().getDeclaredFields(), obj.getClass().getSuperclass().getDeclaredFields());
        root = this.getElementIfExistByValue(pname, idfDmName, mapping);
        if (root == null) return false;
        Element elementBefore = this.getElementIfExist(obj, idfAttrName, root);
        if (elementBefore != null) root.remove(elementBefore);
        Element element = root.addElement(labelSecond);
        Field[] fieldSub = linkArray(obj.getClass().getDeclaredFields(), obj.getClass().getSuperclass().getDeclaredFields());
        for (int j = 0; j < fieldSub.length; j++) {
            element.addAttribute(fieldSub[j].getName(), (String) this.getField(fieldSub[j], obj, dateformat));
        }
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");   // 设置XML文件的编码格式
        FileOutputStream fs = new FileOutputStream(filePath.toString().replace("file:/", ""));
        XMLWriter writer = new XMLWriter(fs, format);
        writer.setEscapeText(false);
        writer.write(document);
        writer.flush();
        writer.close();
        fs.close();
        return true;
    }

    /**
     * 先将已有root和field两层节点删除   再重新写入数据
     *
     * @param obj          对象 包括父子节点 List存储子节点
     * @param filePath     路径
     * @param idfFieldName 识别的属性名
     * @param labelRoot    父节点标签名
     * @param labelSecond  子节点标签名
     */
    @SuppressWarnings("unchecked")
    public void cleanAndWriteXml(Object obj, String filePath, String dateFormat, String idfFieldName, String labelRoot,
                                 String labelSecond) throws DocumentException, IllegalArgumentException, IllegalAccessException, IOException {

        File file = new File(filePath.toString().replace("file:/", ""));
        Element mapping;
        Document document;
        if (!file.exists()) {
            document = DocumentHelper.createDocument();
            mapping = document.addElement("mapping");
        } else {
            SAXReader reader = new SAXReader();
            document = reader.read(file);
            mapping = document.getRootElement();
        }
        Element rootBefore;
        //父子类属性
        Field[] field = this.linkArray(obj.getClass().getDeclaredFields(), obj.getClass().getSuperclass().getDeclaredFields());
        rootBefore = this.getElementIfExist(obj, idfFieldName, mapping);
        if (rootBefore != null) {
            mapping.remove(rootBefore);//如果存在 将原有数据清除
        }
        Element root = mapping.addElement(labelRoot);
        for (int i = 0; i < field.length; i++) { //模型
            if ("interface java.util.List".equals(field[i].getType().toString())) {
                List<Object> list = (List<Object>) this.getField(field[i], obj, dateFormat);
                if (list != null) {
                    for (Object a : list) {  //属性
                        Element element = root.addElement(labelSecond);
                        Field[] fieldSub = this.linkArray(a.getClass().getDeclaredFields(), a.getClass().getSuperclass().getDeclaredFields());
                        for (int j = 0; j < fieldSub.length; j++) {
                            element.addAttribute(fieldSub[j].getName(), (String) this.getField(fieldSub[j], a, dateFormat));
                        }
                    }
                }
            } else {
                root.addAttribute(field[i].getName(), (String) this.getField(field[i], obj, dateFormat));
            }
        }

        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");   // 设置XML文件的编码格式
        FileOutputStream fs = new FileOutputStream(filePath.toString().replace("file:/", ""));
        XMLWriter writer = new XMLWriter(fs, format);
        writer.setEscapeText(false);
        writer.write(document);
        writer.flush();
        writer.close();
        fs.close();
    }

    /**
     * 根据标识属性获取父节点对象
     *
     * @param attrValue   属性值
     * @param idfAttrName 属性名
     * @param className   对象类名
     * @param filePath    路径
     */
    public Object getRootObjByAttr(String attrValue, String idfAttrName, String className, String filePath, String dateformat) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException, ClassNotFoundException, ParseException, DocumentException {
        File file = new File(filePath.toString().replace("file:/", ""));
        if (!file.exists()) {
            return null;
        }
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element mapping = document.getRootElement();
        Element e = this.getElementIfExistByValue(attrValue, idfAttrName, mapping);
        if (e == null) return null;
        return initBean(className, e, false, dateformat, null);
    }

    /**
     * 根据标识属性获取子节点对象
     *
     * @param attrValue   属性值
     * @param pname       父节点名称
     * @param idfAttrName 识别属性名
     * @param className   对象类名
     * @param filePath    路径
     */
    public Object getSecondObjByName(String pname, String idfpAttrName, String attrValue, String idfAttrName, String className,
                                     String filePath, String dateformat) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException, ClassNotFoundException, ParseException, DocumentException {
        File file = new File(filePath.toString().replace("file:/", ""));
        if (!file.exists()) {
            return null;
        }
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element mapping = document.getRootElement();
        Element root = this.getElementIfExistByValue(pname, idfpAttrName, mapping);
        if (root == null) return null;
        Element e = this.getElementIfExistByValue(attrValue, idfAttrName, root);
        if (e == null) return null;
        return initBean(className, e, false, dateformat, null);
    }

    public List<DataModel> getAllWithSon(String className, String secClassName, String filePath, String dateformat) throws DocumentException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException, ClassNotFoundException, ParseException {
        List list = new ArrayList();
        File file = new File(filePath.toString().replace("file:/", ""));
        if (!file.exists()) {
            return list;
        }
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(filePath.toString().replace("file:/", "")));
        Element root = document.getRootElement();

        for (Iterator c = root.elementIterator(); c.hasNext(); ) {
            Element elementSub = (Element) c.next();
            list.add(initBean(className, elementSub, true, dateformat, secClassName));
        }
        return list;
    }
}
